home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Editors / Emacs / Source / EtermView.m < prev    next >
Encoding:
Text File  |  1992-11-30  |  18.1 KB  |  751 lines

  1. /* The EtermView implementation.
  2.  
  3.    For legal stuff see the file COPYRIGHT.  */
  4.  
  5. #import <dpsclient/dpsclient.h>
  6. #import <libc.h>
  7. #import <mach/mach.h>
  8. #import <stdio.h>
  9. #import <stdlib.h>
  10. #import <sys/ioctl.h>
  11. #import <sys/param.h>
  12.  
  13. #import "EtermView.h"
  14. #import "EmacsApp.h"
  15. #import "etermSupport.h"
  16. #import "defaults.h"
  17. #import "display.h"
  18.  
  19. extern char **environ;
  20.  
  21. /* These are the window size limits imposed by GNUEmacs.  */
  22. #define MINWIDTH 10
  23. #define MINHEIGHT 5
  24. #define MAXWIDTH 300
  25. #define MAXHEIGHT 300
  26.  
  27. /* Function prototypes for display.pswm */
  28. void *new_display_rock (EtermView *theView);
  29. void input_from_emacs (int fd, void *theDisplay);
  30.  
  31. /* Function prototypes for keycode.c */
  32. void kc_init (void);
  33. int kc_keyforcode (int code, int flags);
  34.  
  35. /* write(2), except it will keep retrying upon partial success.  */
  36. static int
  37. write_safely (int fd, char *buf, int n)
  38. {
  39.   int i, start = 0;
  40.  
  41.   while (start < n)
  42.     {
  43.       i = write (fd, buf + start, n - start);
  44.       if (i == -1)
  45.     return i; /* Some error */
  46.       start += i;
  47.     }
  48.   return n;
  49. }
  50.  
  51. /* Handle a connection to the event server socket */
  52. static void
  53. connection_from_emacs (int fd, void *rock)
  54. {
  55.   EtermView *view = (EtermView *) rock;
  56.   int newfd = accept_server_connection (fd);
  57.  
  58.   if (newfd == -1)
  59.     return;
  60.  
  61.   if ([view eventChannel])
  62.     close (newfd);
  63.   else
  64.     [view setEventChannel: fdopen (newfd, "w")];
  65. }
  66.  
  67. @implementation EtermView
  68.  
  69. + initialize
  70. {
  71.   static NXDefaultsVector etermDefaults =
  72.     {
  73.       {"NXAutoLaunch", "NO" },
  74.       {"NXFixedPitchFontSpacing", "0.95" },
  75.       {"HideOnAutoLaunch", "NO" },
  76.       {"EmacsPath", DEFAULT_EMACS_PATH},
  77.       {"LispPath", DEFAULT_LISP_PATH},
  78.       {NULL},
  79.     };
  80.   const char *sTypes[2], *rTypes[2];
  81.  
  82.   sTypes[0] = NXAsciiPboardType;
  83.   sTypes[1] = NULL;
  84.   rTypes[0] = NXAsciiPboardType;
  85.   rTypes[1] = NULL;
  86.  
  87.   NXRegisterDefaults ([NXApp appName], etermDefaults);
  88.   [NXApp registerServicesMenuSendTypes: sTypes andReturnTypes: rTypes];
  89.   kc_init ();
  90.  
  91.   return self;
  92. } /* +initialize */
  93.  
  94. -initFrame: (const NXRect *) newFrame
  95. {
  96.   self = [super initFrame: newFrame];
  97.   [self setFlipped: YES];
  98. #if 0
  99.   [self notifyAncestorWhenFrameChanged: YES];
  100. #endif
  101.  
  102.   spacing = atof (NXGetDefaultValue ([NXApp appName],
  103.                      "NXFixedPitchFontSpacing"));
  104.   /* Check for sane values of spacing.  */
  105.   if (spacing < 0.9)
  106.     spacing = 0.9;
  107.   else if (spacing > 2.0)
  108.     spacing = 2.0;
  109.   [self setFont: [self font]];
  110.   [[NXApp fontManager] setSelFont: [self font] isMultiple: NO];
  111.   return self;
  112. } /* -initFrame: */
  113.  
  114. -(float) spacing
  115. {
  116.   return spacing;
  117. }
  118.  
  119. -setSpacing: (float) newSpacing
  120. {
  121.   char val[20];
  122.  
  123.   spacing = newSpacing;
  124.   [self setFont: [self font]];
  125.   sprintf (val, "%f", newSpacing);
  126.   NXWriteDefault ([NXApp appName], "NXFixedPitchFontSpacing", val);
  127.   return self;
  128. }
  129.  
  130. -font
  131. {
  132.   return [Font userFixedPitchFontOfSize: (float) 0 matrix: NX_FLIPPEDMATRIX];
  133. } /* -font */
  134.  
  135. -setFont: newFont
  136. {
  137.   NXCoord ascender, descender, lineHeight;
  138.   NXRect frameRect, contentRect;
  139.   Font *screenfont;
  140.   int leading;
  141.  
  142.   /* NXTextFontInfo is broken for screen fonts, so call it before converting
  143.      the font to a screenfont.  */
  144.   NXTextFontInfo (newFont , &ascender, &descender, &lineHeight);
  145.   screenfont = [newFont screenFont];
  146.   if (screenfont)
  147.     newFont = screenfont;
  148.  
  149.   leading = (spacing - 1.0) * lineHeight;
  150.   fontHeight = (int) (lineHeight * spacing + leading);
  151.   fontWidth = (float) ([newFont getWidthOf : "  "]
  152.                - [newFont getWidthOf : " "] + 0.5);
  153.   fontDescender = (int) (descender + leading);
  154.  
  155.   [newFont set];
  156.   if (screenfont)
  157.     set_font ();
  158.   else
  159.     fix_font (fontWidth);
  160.   displayFont = newFont;
  161.  
  162.   /* Snap the window size to a 1 x 1 character grid.  */
  163.   [window getFrame: &frameRect];
  164.   [self windowWillResize: self toSize: &frameRect.size];
  165.   [Window getContentRect: &contentRect forFrameRect: &frameRect
  166.           style: [window style]];
  167.   [window sizeWindow: contentRect.size.width : contentRect.size.height];
  168.   [self windowDidResize: self];
  169.   [self display];
  170.  
  171.   return self;
  172. } /* -setFont: */
  173.  
  174. /* Sent by fontManager.  */
  175. -changeFont: sender
  176. {
  177.   id selectedFont;
  178.  
  179.   /* Get the font selected in the FontPanel.  */
  180.   selectedFont = [[NXApp fontManager]
  181.           convertFont: [[NXApp fontManager] selFont]];
  182.   [self setFont: selectedFont];
  183.   [Font setUserFixedPitchFont: selectedFont];
  184.   return self;
  185. } /* -changeFont: */
  186.  
  187. -(FILE *) eventChannel;
  188. {
  189.   return eventChannel;
  190. } /* -eventChannel */
  191.  
  192. -setEventChannel: (FILE *) fp;
  193. {
  194.   eventChannel = fp;
  195.   return self;
  196. } /* -setEventChannel: */
  197.  
  198. /* Constrain window so that the content view has an integral width in terms
  199.    of characters.  XXX this method needs some cleaning up to stop the window
  200.    from flashing while resizing.  */
  201. -windowWillResize: sender toSize: (NXSize *) frameSize;
  202. {
  203.   static int oldw = 0, oldh = 0;
  204.   int neww, newh;
  205.   NXRect frameRect, contentRect;
  206.   int newwidth, newheight;
  207.   int style = [window style];
  208.  
  209.   NXSetRect (&frameRect, 0.0, 0.0, frameSize->width, frameSize->height);
  210.   [Window getContentRect: &contentRect forFrameRect: &frameRect style: style];
  211.  
  212.   newwidth = (int) (contentRect.size.width + fontWidth / 2 - BORDER_WIDTH * 2);
  213.   newheight = (int) (contentRect.size.height
  214.              + fontHeight / 2 - BORDER_WIDTH * 2);
  215.  
  216.   newwidth -= newwidth % fontWidth;
  217.   newheight -= newheight % fontHeight;
  218.  
  219.   if (newwidth < MINWIDTH * fontWidth)
  220.     newwidth = MINWIDTH * fontWidth;
  221.   if (newwidth > MAXWIDTH * fontWidth)
  222.     newwidth = MAXWIDTH * fontWidth;
  223.  
  224.   if (newheight < MINHEIGHT * fontHeight)
  225.     newheight = MINHEIGHT * fontHeight;
  226.   if (newheight > MAXHEIGHT * fontHeight)
  227.     newheight = MAXHEIGHT * fontHeight;
  228.  
  229.   contentRect.size.width = (NXCoord) newwidth + BORDER_WIDTH * 2;
  230.   contentRect.size.height = (NXCoord) newheight + BORDER_WIDTH * 2;
  231.   [Window getFrameRect:&frameRect forContentRect:&contentRect style:style];
  232.  
  233.   frameSize->width = frameRect.size.width;
  234.   frameSize->height = frameRect.size.height;
  235.  
  236.   newh = newheight / fontHeight;
  237.   neww = newwidth / fontWidth;
  238.   if (newh != oldh || neww != oldw)
  239.     {
  240.       [self showTitle: newh : neww];
  241.       oldh = newh;
  242.       oldw = neww;
  243.     }
  244.   return self;
  245. } /* -windowWillResize:toSize: */
  246.  
  247. /* Convert size to number of characters in content view.  Inform child emacs
  248.    process of our new size.  */
  249. -windowDidResize: sender
  250. {
  251.   NXRect frameRect, contentRect;
  252.   int style = [window style];
  253.   struct winsize winsize;
  254.  
  255.   [window getFrame: &frameRect];
  256.   [Window getContentRect: &contentRect forFrameRect: &frameRect style: style];
  257.  
  258.   lines = (int) ((contentRect.size.height - BORDER_WIDTH * 2) / fontHeight);
  259.   cols =  (int) ((contentRect.size.width - BORDER_WIDTH * 2) / fontWidth);
  260.   [self showTitle: lines : cols];
  261.  
  262.   /* emacs doesn't do anything with a TIOCCSWINSZ if LINES nor COLS change,
  263.      so send a redraw screen in that case.  */
  264.   winsize.ws_row = lines;
  265.   winsize.ws_col = cols;
  266.   winsize.ws_xpixel = (int) contentRect.size.width;
  267.   winsize.ws_ypixel = (int) contentRect.size.height;
  268.   ioctl (masterChannel, TIOCSWINSZ, &winsize);
  269.   if (eventChannel)
  270.     fprintf (eventChannel, "(redraw-display)\n");
  271.   return self;
  272. } /* -windowDidResize: */
  273.  
  274. /* Start up the child emacs process, perhaps on a file.  */
  275. -startEmacs: (char **) files : (int) nfiles
  276. {
  277.   int master, slave, ptynumber, portno, i, n;
  278.   char **args, **env;
  279.   char *lisp, *path;
  280.  
  281.   /* Grab a pty/tty pair */
  282.   create_channel (&master, &slave, &ptynumber);
  283.   masterChannel = master;
  284.  
  285.   /* Create the server socket */
  286.   eventServerSocket = create_server_socket (&portno);
  287.   DPSAddFD (eventServerSocket, connection_from_emacs,
  288.         (void *) self, NX_RUNMODALTHRESHOLD);
  289.  
  290.   /* Frob the environment */
  291.   env = patch_env (environ, portno);
  292.  
  293.   /* Make sure the size is set correctly */
  294.   [self windowDidResize: self];
  295.  
  296.   args = calloc (nfiles + 6, sizeof (char *));
  297.   args[0] = "emacs";
  298.  
  299.   path = malloc (MAXPATHLEN + 1);
  300.   lisp = NXGetDefaultValue ([NXApp appName], "LispPath");
  301.   args[1] = "-l";
  302.   args[3] = "-f";
  303.   args[4] = "start-event-server";
  304.   n = 5;
  305.   if (strrchr (lisp, '/'))
  306.     args[2] = lisp;
  307.   else
  308.     {
  309.       if ([[NXBundle mainBundle] getPath: path forResource: lisp ofType: NULL])
  310.     args[2] = path;
  311.       else
  312.     n = 1;
  313.     }
  314.  
  315.   for (i = 0; i < nfiles; i++, n++)
  316.     args[n] = files[i];
  317.  
  318.   /* Fork off the Emacs */
  319.   fork_shell (NXGetDefaultValue ([NXApp appName], "EmacsPath"),
  320.           args, env, slave);
  321.   free (path);
  322.   free (args);
  323.   close (slave);
  324.  
  325.   DPSAddFD (master, input_from_emacs, new_display_rock (self),
  326.         NX_RUNMODALTHRESHOLD);
  327.   [window display];
  328.   return self;
  329. } /* -startEmacs: */
  330.  
  331. -(BOOL) acceptsFirstResponder
  332. {
  333.   return YES;
  334. } /* -acceptsFirstResponder */
  335.  
  336. /* Keyboard input is given to the child emacs process.  XXX this method needs some cleeaning up.  */
  337. -keyDown: (NXEvent *) theEvent;
  338. {
  339.   NXEvent eventbuf;
  340.   char buf[1024];
  341.   int i = 0;
  342.   int code;
  343.   int start = 0;
  344.  
  345.   if (theEvent->flags & NX_NUMERICPADMASK
  346.       && theEvent->data.key.charCode >= 0xac
  347.       && theEvent->data.key.charCode <= 0xaf)
  348.     {
  349.       /* Arrow keys (left, up, right, down) */
  350.       if (theEvent->flags & NX_SHIFTMASK)
  351.     buf[i++] = "\302\326\306\026"[theEvent->data.key.charCode - 0xac];
  352.       else if (theEvent->flags & NX_CONTROLMASK)
  353.     buf[i++] = "\001\274\005\276"[theEvent->data.key.charCode - 0xac];
  354.       else if (theEvent->flags & NX_ALTERNATEMASK)
  355.     buf[i++] = "\202\220\206\216"[theEvent->data.key.charCode - 0xac];
  356.       else
  357.     buf[i++] = "\002\020\006\016"[theEvent->data.key.charCode - 0xac];
  358.     }
  359.   else if (theEvent->flags & NX_NUMERICPADMASK
  360.        && theEvent->data.key.charCode == 0x03)
  361.     {
  362.       /* Enter key */
  363.       buf[i++] = '\r';
  364.     }
  365.   else if (theEvent->flags & NX_ALTERNATEMASK)
  366.     {
  367.       /* Handle ALT key as a META key */
  368.       code = kc_keyforcode(theEvent->data.key.keyCode, theEvent->flags);
  369.       if (code != -1) {
  370.     buf[i++] = code | 0x80;
  371.       }
  372.     }
  373.   else buf[i++] = theEvent->data.key.charCode;
  374.  
  375.   /* Grab as many keypressed events as we can from a modal event loop */
  376.   while (i < sizeof (buf)
  377.      && (theEvent = [NXApp peekNextEvent: NX_ALLEVENTS into: &eventbuf])
  378.      && theEvent->type == NX_KEYDOWN
  379.      && !(theEvent->flags & NX_COMMANDMASK))
  380.     {
  381.       theEvent = [NXApp getNextEvent: NX_ALLEVENTS];
  382.  
  383.       if (theEvent->flags & NX_NUMERICPADMASK
  384.       && theEvent->data.key.charCode >= 0xac
  385.       && theEvent->data.key.charCode <= 0xaf)
  386.     {
  387.       /* Arrow keys (left, up, right, down) */
  388.       if (theEvent->flags & NX_SHIFTMASK)
  389.         buf[i++] = "\302\326\306\026"[theEvent->data.key.charCode - 0xac];
  390.       else if (theEvent->flags & NX_CONTROLMASK)
  391.         buf[i++] = "\001\274\005\276"[theEvent->data.key.charCode - 0xac];
  392.       else if (theEvent->flags & NX_ALTERNATEMASK)
  393.         buf[i++] = "\202\220\206\216"[theEvent->data.key.charCode - 0xac];
  394.       else
  395.         buf[i++] = "\002\020\006\016"[theEvent->data.key.charCode - 0xac];
  396.     }
  397.       else if (theEvent->flags & NX_NUMERICPADMASK
  398.            && theEvent->data.key.charCode == 0x03)
  399.     {
  400.       /* Enter key */
  401.       buf[i++] = '\r';
  402.     }
  403.       else if (theEvent->flags & NX_ALTERNATEMASK)
  404.     {
  405.       /* Handle ALT key as a META key */
  406.       code = kc_keyforcode (theEvent->data.key.keyCode, theEvent->flags);
  407.       if (code != -1)
  408.         buf[i++] = code | 0x80;
  409.     }
  410.       else buf[i++] = theEvent->data.key.charCode;
  411.     }
  412.  
  413.   write_safely (masterChannel, buf, i);
  414.   obscure_cursor ();
  415.  
  416.   return self;
  417. } /* -keyDown: */
  418.  
  419. /* Mouse input is converted to a character position and given to the child
  420.    emacs process, but only if the emacs has opened an event port.  */
  421. -mouseEvent: (NXEvent *) theEvent : (int) button;
  422. {
  423.   int x, y;
  424.   char buf[35];
  425.  
  426.   if (!eventChannel)
  427.     return self;
  428.  
  429.   [self convertPoint: &theEvent->location fromView:nil];
  430.   x = (int) ((theEvent->location.x - BORDER_WIDTH) / fontWidth);
  431.   y = (int) ((theEvent->location.y - BORDER_WIDTH) / fontHeight);
  432.  
  433.   if (x < 0)
  434.     x = 0;
  435.   if (y < 0)
  436.     y = 0;
  437.   if (x >= cols)
  438.     x = cols - 1;
  439.   if (y >= lines)
  440.     y = lines - 1;
  441.  
  442.   sprintf (buf, "\030%c(%d %d %d 1)\r", 0,
  443.        (button + ((theEvent->flags & NX_SHIFTMASK) ? 8 : 0)
  444.         + ((theEvent->flags & NX_CONTROLMASK) ? 16 : 0)
  445.         + ((theEvent->flags & NX_ALTERNATEMASK) ? 32 : 0)), x, y);
  446.   write_safely (masterChannel, buf, 2+strlen (buf+2));
  447.  
  448.   return self;
  449. } /* -mouseEvent:: */
  450.  
  451.  
  452. -mouseDown: (NXEvent *) theEvent;
  453. {
  454.   [self mouseEvent: theEvent: 1];
  455.   return self;
  456. } /* -mouseDown: */
  457.  
  458. -mouseUp: (NXEvent *) theEvent;
  459. {
  460.   [self mouseEvent: theEvent: 1 + 128];
  461.   return self;
  462. } /* -mouseUp */
  463.  
  464. -rightMouseDown: (NXEvent *) theEvent;
  465. {
  466.   [self mouseEvent: theEvent: 4];
  467.   return self;
  468. } /* rightMouseDown: */
  469.  
  470. -rightMouseUp: (NXEvent *) theEvent;
  471. {
  472.   [self mouseEvent: theEvent: 4 + 128];
  473.   return self;
  474. } /* rightMouseUp: */
  475.  
  476. -(BOOL) emacsOn
  477. {
  478.   if (eventChannel)
  479.     return YES;
  480.   else
  481.     return NO;
  482. } /* -emacsOn */
  483.  
  484. -(BOOL) newFile: (const char *) path
  485. {
  486.   if (!eventChannel)
  487.     return NO;
  488.   fprintf (eventChannel, "(find-file \"%s\")\n", path);
  489.   fflush (eventChannel);
  490.   return YES;
  491. } /* -newFile: */
  492.     
  493. /* Quit, cut, copy, paste, and undo messages are sent to the child's event
  494.    port.  */
  495. -quitEmacs
  496. {
  497.   if (!eventChannel)
  498.     return nil;
  499.   fprintf (eventChannel, "(event-quit)\n");
  500.   fflush (eventChannel);
  501.   return self;
  502. } /* -quitEmacs */
  503.  
  504. -pasteboard
  505. {
  506.   return currentPasteboard;
  507. } /* -pasteboard */
  508.  
  509. -appPasteboard
  510. {
  511.   if (!mainPasteboard)
  512.     mainPasteboard = [Pasteboard new];
  513.   return mainPasteboard;
  514. } /* -appPasteboard */
  515.  
  516. -setPasteboard: pboard
  517. {
  518.   currentPasteboard = pboard;
  519.   return self;
  520. } /* -setPasteboard: */
  521.  
  522. -(BOOL) sendEmacsEvent: (char *) theEvent
  523. {
  524.   if (!eventChannel)
  525.     return NO;
  526.   fprintf (eventChannel, "%s\n", theEvent);
  527.   fflush (eventChannel);
  528.   return YES;
  529. } /* -(BOOL) sendEmacsEvent: */
  530.  
  531. -undo: sender;
  532. {
  533.   [self sendEmacsEvent: "(undo)"];
  534.   return self;
  535. } /* -undo: */
  536.  
  537. -save: sender;
  538. {
  539.   [self sendEmacsEvent: "(save-buffer)"];
  540.   return self;
  541. } /* -save: */
  542.  
  543. -saveAll: sender;
  544. {
  545.   [self sendEmacsEvent: "(save-some-buffers t)"];
  546.   return self;
  547. } /* -saveAll: */
  548.  
  549. -cut: sender;
  550. {
  551.   [self cutTo: [self appPasteboard]];
  552.   return self;
  553. } /* -cut: */
  554.  
  555. -copy: sender;
  556. {
  557.   [self copyTo: [self appPasteboard]];
  558.   return self;
  559. } /* -copy: */
  560.  
  561. -paste: sender;
  562. {
  563.   [self pasteFrom: [self appPasteboard]];
  564.   return self;
  565. } /* -paste: */
  566.  
  567. -open: sender;
  568. {
  569.   int i;
  570.   char *path;
  571.   const char *directory;
  572.   const char *const *fileNames;
  573.  
  574.   if (!eventChannel)
  575.     return self;
  576.   if (!openPanel)
  577.     openPanel = [OpenPanel new];
  578.   [openPanel allowMultipleFiles: YES];
  579.   [openPanel chooseDirectories: NO];
  580.   if ([openPanel runModal])
  581.     {
  582.       directory = [openPanel directory];
  583.       fileNames = [openPanel filenames];
  584.       if (fileNames)
  585.     {
  586.       for (i = 0; fileNames[i]; i++)
  587.         {
  588.           path = malloc (2 + strlen (directory) + strlen (fileNames[i]));
  589.           strcat (strcat (strcpy (path, directory), "/"), fileNames[i]);
  590.           fprintf (eventChannel, "(find-file \"%s\")\n", path);
  591.           fflush (eventChannel);
  592.           free (path);
  593.         }
  594.     }
  595.     }
  596.   return self;
  597. } /* -open: */
  598.  
  599. -saveAs: sender;
  600. {
  601.   const char *path;
  602.  
  603.   if (!eventChannel)
  604.     return self;
  605.   if (!savePanel)
  606.     savePanel = [SavePanel new];
  607.   if ([savePanel runModal])
  608.     {
  609.       path = [savePanel filename];
  610.       if (path)
  611.     {
  612.       fprintf (eventChannel, "(write-file \"%s\")\n", path);
  613.       fflush (eventChannel);
  614.     }
  615.     }
  616.   return self;
  617. } /* -saveAs: */
  618.  
  619. -(BOOL) cutTo: pasteboard
  620. {
  621.   return [[self setPasteboard: pasteboard] sendEmacsEvent: "(event-cut)"];
  622. } /* -(BOOL) cutTo: */
  623.  
  624. -(BOOL) copyTo: pasteboard
  625. {
  626.   return [[self setPasteboard: pasteboard] sendEmacsEvent: "(event-copy)"];
  627. } /* -(BOOL) copyTo: */
  628.  
  629. -(BOOL) pasteFrom: pasteboard
  630. {
  631.   const NXAtom *types, *p;
  632.   char *data;
  633.   int len;
  634.  
  635.   if (!eventChannel || !pasteboard)
  636.     return NO;
  637.   types = [pasteboard types];
  638.   for (p = types; *p && strcmp (*p, NXAsciiPboardType); p++);
  639.  
  640.   if (*p && [pasteboard readType: NXAsciiPboardType data: &data length: &len]
  641.       && len)
  642.     {
  643.       int c;
  644.       char *tosend = data;
  645.  
  646.       fputs("(event-paste \"", eventChannel);
  647.  
  648.       /* Write out string, quoting quote, backslash, and newline */
  649.       for (tosend = data; len--; tosend++)
  650.     {
  651.       switch (c = *tosend)
  652.         {
  653.         case '\n':
  654.           fputs ("\\n", eventChannel);
  655.           break;
  656.         case '\\':
  657.         case '\"':
  658.           putc('\\', eventChannel);
  659.           /* FALL THROUGH */
  660.         default:
  661.           putc (c, eventChannel);
  662.           break;
  663.         }
  664.     }
  665.       fputs ("\")\n", eventChannel);
  666.       fflush (eventChannel);
  667.       vm_deallocate (task_self (), (vm_address_t) data, len);
  668.     }
  669.   return YES;
  670. } /* -(BOOL) pasteFrom: */
  671.  
  672. -getDimensions: (int *) linesPtr : (int *) colsPtr
  673. {
  674.   *linesPtr = lines;
  675.   *colsPtr = cols;
  676.   return self;
  677. } /* -getDimensions:: */
  678.  
  679. -(Font *) getDisplayFont:
  680.   (int *) heightPtr :
  681.   (int *) widthPtr :
  682.   (int *) descenderPtr
  683. {
  684.   *heightPtr = fontHeight;
  685.   *widthPtr = fontWidth;
  686.   *descenderPtr = fontDescender;
  687.   return displayFont;
  688. } /* -getDisplayFont::: */
  689.  
  690. -showTitle: (int) newLines : (int) newColumns
  691. {
  692.   char *newtitle;
  693.  
  694.   if (!titleprefix)
  695.     return self;
  696.   newtitle = malloc (22 + strlen (titleprefix));
  697.   sprintf (newtitle, "%s (%dx%d)", titleprefix, newColumns, newLines);
  698.   [(Window *) window setTitle: newtitle];
  699.   free (newtitle);
  700.   return self;
  701. } /* -showTitle:: */
  702.  
  703. -setTitle: (char *) title
  704. {
  705.   titleprefix = title;
  706.   [self showTitle: lines : cols];
  707.   return self;
  708. } /* -setTitle: */
  709.  
  710. -validRequestorForSendType: (NXAtom) typeSent
  711.  andReturnType: (NXAtom) typeReturned
  712. {
  713.   /* Check to make sure that the types are ones that we can handle.  */
  714.   if (eventChannel && (typeSent == NXAsciiPboardType || typeSent == NULL)
  715.       && (typeReturned == NXAsciiPboardType || typeReturned == NULL))
  716.     return self;
  717.   /* Otherwise, return the default.  */
  718.   return [super validRequestorForSendType: typeSent
  719.                 andReturnType: typeReturned];
  720. } /* -validRequestorForSendType:andReturnType: */
  721.  
  722. -(BOOL) writeSelectionToPasteboard: pboard types: (NXAtom *) types
  723. {
  724.   const NXAtom *p;
  725.  
  726.   if (eventChannel && pboard)
  727.     {
  728.       for (p = types; *p && strcmp (*p, NXAsciiPboardType); p++);
  729.       if (*p)
  730.     {
  731. /* We should have the pasteboard data ready before returning here, how?  */
  732. #if 0
  733.       [pboard declareTypes: &NXAsciiPboardType
  734.               num: 1
  735.               owner: NULL];
  736. #endif
  737.       return [self copyTo: pboard];
  738.     }
  739.     }
  740.   return NO;
  741. } /* -writeSelectionToPasteboard:types: */
  742.  
  743. -readSelectionFromPasteboard: pboard
  744. {
  745.   [self sendEmacsEvent: "(kill-region (mark) (point))"];
  746.   [self pasteFrom: pboard];
  747.   return self;
  748. } /* -readSelectionFromPasteboard: */
  749.  
  750. @end
  751.